home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / sound / adda10.zip / ADDA.PAS < prev    next >
Pascal/Delphi Source File  |  1992-09-24  |  9KB  |  344 lines

  1. program ADDA(Input, Output);
  2.  
  3. { This program is to be used in conjunction with the analog extension
  4.   board described in the note "ANALOG I/O BOARD FOR PC'S". It is assumed
  5.   that the AD7569 is operated in one of its two bipolar modes (-1.25 V -->
  6.   +1.25 V or -2.5 --> +2.5 V). }
  7.  
  8. uses Dos, Crt, Graph;
  9.  
  10. const Title= 'ADDA V1.0 - Jos Groot (September 24, 1992)';
  11.  
  12. {$R-} { this prevents Turbo Pascal from complaining about putting a Byte
  13.         into a ShortInt type variable }
  14.  
  15. const Status = $300 ;  { bit 0 is 1 when an AD conversion is going on and
  16.                         becomes 0 upon completion of the conversion }
  17.       ADC    = $301 ;  { read : get result of most recently completed AD
  18.                         conversion and start the next }
  19.       DAC    = ADC  ;  { write: start DA conversion }
  20.       Max_Sam= 60000;  { maximum number of samples }
  21.  
  22. var Buf: array[0..Max_Sam] of ShortInt; { global array receiving samples }
  23.  
  24. { ******* }
  25.  
  26. procedure Initialize_Graphics;
  27.  
  28. { initializes graphics mode }
  29.  
  30. var GraphMode, GraphDriver, ErrorCode: Integer;
  31.  
  32. begin
  33.   GraphDriver:= Detect;
  34.   InitGraph(GraphDriver,GraphMode,'.');
  35.   ErrorCode:= GraphResult;
  36.  
  37.   if ErrorCode<> GrOk then
  38.   begin
  39.     WriteLn; WriteLn;
  40.     WriteLn('Graphics error: ', GraphErrorMsg(ErrorCode));
  41.     WriteLn('Sorry, I have to quit...');
  42.     Halt(1)
  43.   end;
  44.  
  45.   SetColor(White)
  46. end;
  47.  
  48. { ******* }
  49.  
  50. procedure Flush_Keyboard_Buffer;
  51.  
  52. { flushes the keyboard buffer by reading all pending characters }
  53.  
  54. var Kar: Char;
  55.  
  56. begin
  57.   while KeyPressed do Kar:= ReadKey
  58. end;
  59.  
  60. { ******* }
  61.  
  62. procedure Get_Samples(Samples: Word);
  63.  
  64. { reads as fast as possible samples 0,1,...,Samples into array Buf. Sample
  65.   Buf[0] should not be used, because this is the ADC result of a conversion
  66.   started at an unknown earlier time. }
  67.  
  68. var i: Word;
  69.     Pause: Integer;
  70.  
  71. begin
  72.   for i:= 0 to Samples do { start at 0, 1 is the first good sample to use }
  73.   begin
  74.     asm   { small delay to enable the ADC to complete a conversion before  }
  75.       nop { reading the result. The necessity and length of this delay may }
  76.       nop { vary for different AD7569's. }
  77.       nop
  78.     end;
  79.  
  80. {   for Pause:= 1 to 50 do;} { add this loop to decrease sampling frequency }
  81.  
  82.     Buf[i]:= Port[ADC] { get and store sample & initiate next conversion }
  83.   end
  84. end;
  85.  
  86. { ******* }
  87.  
  88. procedure Compute_Statistics(Samples: Word;
  89.                              var Average, RMS_Amp: Real;
  90.                              var Min, Max: ShortInt);
  91.  
  92. { computes the average, RMS amplitude, minimum and maximum of the samples
  93.   Buf[1], Buf[2], ..., Buf[Samples] }
  94.  
  95. var s: ShortInt;
  96.     i: Word;
  97.     Sum, Sum2: Real;
  98.  
  99. begin
  100.   Sum :=    0;
  101.   Sum2:=    0; { sum of squares }
  102.   Min :=  127;
  103.   Max := -128;
  104.  
  105.   for i:= 1 to Samples do
  106.   begin
  107.     s:= Buf[i];
  108.     Sum := Sum  + s;
  109.     Sum2:= Sum2 + Sqr(s);
  110.     if s< Min then Min:= s;
  111.     if s> Max then Max:= s
  112.   end;
  113.  
  114.   Average:= Sum/Samples;
  115.   RMS_Amp:= Sqrt(Sum2/Samples - Sqr(Average))
  116. end;
  117.  
  118. { ******* }
  119.  
  120. procedure Sampling_Frequency(var Fs: Real);
  121.  
  122. { computes the sampling frequency Fs of procedure Get_Samples from the time
  123.   it takes to measure n*Max_Sam samples }
  124.  
  125. const n= 20;
  126.  
  127. var h, m, s, s100: Word;
  128.     i: Integer;
  129.     Start, Duration: LongInt;
  130.  
  131. begin
  132.   WriteLn; WriteLn; WriteLn;
  133.   Write('Taking ', n*Max_Sam:1, ' samples at ... ');
  134.   Gettime(h, m, s, s100);
  135.   Start:= Round(360000.0*h+6000.0*m+100.0*s+s100);
  136.  
  137.   for i:= 1 to n do Get_Samples(Max_Sam);
  138.  
  139.   Gettime(h, m, s, s100);
  140.   Duration:= Round(360000.0*h+6000.0*m+100.0*s+s100) - Start;
  141.   Fs:= n*Max_Sam/Duration/10;
  142.   Write(Fs:1:1, ' KHz sampling frequency approximately.');
  143.  
  144.   repeat until KeyPressed
  145. end;
  146.  
  147. { ******* }
  148.  
  149. procedure Plot_Samples;
  150.  
  151. { takes samples and plots these with some statistical information }
  152.  
  153. var x, CenterY, MinY, MaxY, Samples: Integer;
  154.     Min, Max: ShortInt;
  155.     Average, RMS_Amp: Real;
  156.     Ave, RMS, Mi, Ma: String[6];
  157.  
  158. begin
  159.   Initialize_Graphics;
  160.  
  161.   Samples:= GetMaxX+1;    { number of samples to take and plot    }
  162.  
  163.   CenterY:= GetMaxY div 2;
  164.   MinY:= CenterY-127;     { Y coordinate for most positive sample }
  165.   MaxY:= CenterY+128;     { Y coordinate for most negative sample }
  166.  
  167.   MoveTo(0, MinY-1);      { border line for most positive sample  }
  168.   LineTo(GetMaxX, MinY-1);
  169.   MoveTo(0, MaxY+1);      { border line for most negative sample  }
  170.   LineTo(GetMaxX, MaxY+1);
  171.  
  172.   SetViewPort(0, MinY, GetMaxX, MaxY, Clipoff);
  173.   OutTextXY(0, -40, 'minimum/maximum/average/RMS amplitude: ');
  174.   SetFillStyle(EmptyFill, Black);
  175.  
  176.   repeat
  177.     Get_Samples(Samples);
  178.  
  179.     MoveTo(0, 127-Buf[1]);
  180.     for x:= 2 to Samples do LineTo(x, 127-Buf[x+1]); { plot samples }
  181.  
  182.     { compute and print some statistical information }
  183.  
  184.     Compute_Statistics(Samples, Average, RMS_Amp, Min, Max);
  185.     Str(Average:1:2, Ave);
  186.     Str(RMS_Amp:1:2, RMS);
  187.     Str(Min:1, Mi);
  188.     Str(Max:1, Ma);
  189.     Bar(308, -40, 480, -32); { whipe previous values from the screen }
  190.     OutTextXY(308, -40, Mi + ' ' + Ma + ' ' + Ave + ' ' + RMS);
  191.  
  192.     Delay(1000);
  193.     ClearviewPort { only the data area is cleared }
  194.   until KeyPressed;
  195.  
  196.   CloseGraph
  197. end;
  198.  
  199. { ******* }
  200.  
  201. procedure ADC_To_DAC;
  202.  
  203. { reroutes ADC input directly to DAC output }
  204.  
  205. begin
  206.   repeat
  207.     Port[ADC]:= Port[DAC]
  208.   until KeyPressed
  209. end;
  210.  
  211. { ******* }
  212.  
  213. procedure Distortion;
  214.  
  215. { reads ADC values, and outputs 100 to the DAC for the ones with absolute
  216.   value>= Clip_Level. This produces a compressed and heavily distorted
  217.   sound. }
  218.  
  219. const Clip_Level= 10; { should at least exceed the maximum value of absolute
  220.                         noise samples }
  221.  
  222. var s: ShortInt;
  223.     Table: array[-128..127] of ShortInt; { lookup table for fast execution }
  224.  
  225. begin
  226.   for s:= -128 to 127 do
  227.     if s>  Clip_Level then Table[s]:= 100 else
  228.     if s< -Clip_Level then Table[s]:= 100 else { -100 for softer distortion }
  229.                            Table[s]:= Abs(Round(s/Clip_Level*100));
  230.  
  231.   repeat
  232.     Port[DAC]:= Table[ShortInt(Port[ADC])]
  233.   until KeyPressed
  234. end;
  235.  
  236. { ******* }
  237.  
  238. procedure Echo;
  239.  
  240. { produces an echo by adding ADC samples from some time ago to the present
  241.   samples, and outputting the result to the DAC }
  242.  
  243. var i, j, d: Word;
  244.     k, s, Pause, Buffers: Integer;
  245.     Table: array[-128..127] of Integer; { lookup table for fast execution }
  246.     Dr: Real;
  247.  
  248. begin
  249.   Pause  := 20   ; { Pause determines the sampling frequency (40 kHz)       }
  250.   d      := 20000; { d and Pause determine the delay time (20E3/40E3=0.5 s) }
  251.   Dr     := 0.5  ; { Dr is inversely proportional to the decay rate         }
  252.   Buffers:= 0    ; { number of Max_Sam byte Buffers processed               }
  253.  
  254.   for i:= 0 to Max_Sam do Buf[i]:= 0;            { clear buffer }
  255.   for k:= -128 to 127 do Table[k]:= Round(Dr*k); { fill table }
  256.  
  257.   WriteLn; WriteLn; WriteLn;
  258.   Write('Number of ', Max_Sam:1, ' byte buffers processed: ');
  259.  
  260.   repeat
  261.     GotoXY(41,16);    { print the number of processed buffers indicating }
  262.     Write(Buffers:1); { the sampling frequency }
  263.     Inc(Buffers);
  264.  
  265.     for i:= 0 to Max_Sam do
  266.     begin
  267.       for k:= 1 to Pause do;                      { lower sampling frequency }
  268.       if i>=d then j:= i-d else j:= i-d+Max_Sam+1; { j= index delayed sample }
  269.       s:= ShortInt(Port[ADC]) + Table[Buf[j]];     { compute original + echo }
  270.       if s<-128 then s:= -128 else if s>127 then s:= 127; { correct overflow }
  271.       Buf[i]:= s;                                  { store compound sample   }
  272.       Port[DAC]:= s                                { output sample to DAC    }
  273.     end
  274.   until KeyPressed
  275. end;
  276.  
  277. { ******* }
  278.  
  279. procedure Quit;
  280.  
  281. { resets DAC output to 0 Volts and halts program }
  282.  
  283. begin
  284.   Port[DAC]:= 0;
  285.   Halt
  286. end;
  287.  
  288. { ******* }
  289.  
  290. procedure Menu;
  291.  
  292. { presents the user different actions to choose from }
  293.  
  294. var i, Choice: Integer;
  295.     Fs: Real; { sampling frequency determined by menu item 1 }
  296.  
  297. begin
  298.   Fs:= 0; { sampling frequency not yet determined }
  299.  
  300.   repeat
  301.     ClrScr;
  302.  
  303.     for i:= 1 to Length(Title)+4 do Write('*');
  304.     WriteLn;